<?php

/**
 * @package Framework03
 * @author Walter Tamboer
 */

/**
 * The framework class, this is where the magic happens
 */
final class Framework03 extends Object
{
	/**
	 * @var int The major version of the framework.
	 */
	public static $MarjorVersion = '0';
	/**
	 * @var int The minor version of the framework.
	 */
	public static $MinorVersion = '3';
	/**
	 * Initializes a new instance of this class.
	 */
	public function __construct()
	{
		error_reporting(E_ALL | E_STRICT);

		date_default_timezone_set(Settings::Singleton()->Get('timezone'));

		$Result = set_error_handler(array($this, 'ErrorHandler'));
	}
	/**
	 * Convert a PHP error number to a string
	 * @param int $ErrNo The error number to lookup.
	 * @return string Returns the string of the error number.
	 */
	public static function PhpErrorToString($ErrNo)
	{
		switch ($ErrNo)
		{
		case 1: 	return 'E_ERROR';
		case 2: 	return 'E_WARNING';
		case 4: 	return 'E_PARSE';
		case 8:	 	return 'E_NOTICE';
		case 16:	return 'E_CORE_ERROR';
		case 32: 	return 'E_CORE_WARNING';
		case 64: 	return 'E_COMPILE_ERROR';
		case 128: 	return 'E_COMPILE_WARNING';
		case 256: 	return 'E_USER_ERROR';
		case 512: 	return 'E_USER_WARNING';
		case 1024: 	return 'E_USER_NOTICE';
		case 2048: 	return 'E_STRICT';
		case 4096: 	return 'E_RECOVERABLE_ERROR';
		case 8191: 	return 'E_ALL';
		}
	}
	/**
	 * The PHP error handler to use in case of a PHP error.
	 * @param int $ErrNo The PHP error number.
	 * @param string $ErrStr The PHP error string.
	 * @param string $ErrFile The file where the error did occur.
	 * @param int $ErrLine The line number of the file where the error did occur.
	 */
	public function ErrorHandler($ErrNo, $ErrStr, $ErrFile, $ErrLine)
	{
		if ($ErrNo == 2048 || !Settings::Singleton()->Get('debug'))
			return;

		echo '<h3>' . Framework03::PhpErrorToString($ErrNo) . '</h3>';
		echo '<p>';
		echo 'File: ' . $ErrFile . '<br />';
		echo 'Line: ' . $ErrLine . '<br />';
		echo '</p>';
		echo '<p>';
		echo $ErrStr;
		echo '</p>';
	}
	/**
	 * Get the root path
	 * @return string
	 */
	public static function GetPath()
	{
		return dirname($_SERVER[ 'SCRIPT_FILENAME' ]);
	}
	/**
	 * Gets the current URL.
	 * @return string Returns a string with the current URL.
	 */
	public static function GetUrl()
	{
		$Protocol = (isset($_SERVER[ 'HTTPS' ])) ? 'https' : 'http';

		$URL = $Protocol . '://' . $_SERVER[ 'HTTP_HOST' ] . dirname($_SERVER[ 'SCRIPT_NAME' ]);

		if (substr($URL, -1) == '/')
			$URL = substr($URL, 0, -1);

		return $URL;
	}
	/**
	 * Gets the path information.
	 * @return array Returns an array with the path information.
	 */
	private function GetPathInfo()
	{
		// We use the PATH_INFO var to determine the page
		$PathInfo = empty($_SERVER[ 'PATH_INFO' ]) ? '' : $_SERVER[ 'PATH_INFO' ];

		// Create an array of it.
		$PathInfoArr = explode('/', $PathInfo);

		// Remove the empty elements in the array.
		while (isset($PathInfoArr[0]) && trim($PathInfoArr[0]) == '')
			array_shift($PathInfoArr);

		return $PathInfoArr;
	}
	/**
	 * Gets the controller or returns the default one if no controller is set.
	 * @return string Returns a string with the name of the current controller.
	 */
	private function GetController()
	{
		$PathInfo = $this->GetPathInfo();

		if (count($PathInfo) < 1)
			return Settings::Singleton()->Get('defaultController');

		return strtolower($PathInfo[0]);
	}
	/**
	 * Gets the action that the user requested.
	 * @param Controller $Object The current controller object.
	 * @param array $PathInfo The path info that currently is set.
	 * @return string Returns a string with the name of the requested action.
	 */
	private function GetFunction(Controller $Object, array &$PathInfo = null)
	{
		if (!$PathInfo)
		{
			$PathInfo = $this->GetPathInfo();

			array_shift($PathInfo);
		}

		$Function = implode('_', $PathInfo);

		if (!method_exists($Object, $Function) || method_exists('Controller', $Function))
		{
			array_pop($PathInfo);

			if (count($PathInfo) < 1)
				return Settings::Singleton()->Get('defaultAction');

			return $this->GetFunction($Object, $PathInfo);
		}

		return $Function;
	}
	/**
	 * Gets the arguments that are set to the current action.
	 * @param Controller $Object The current controller object.
	 * @param array $PathInfo The path info that currently is set.
	 * @return array Returns an array with al the arguments of the current action.
	 */
	private function GetArgumentList(Controller $Object, array &$PathInfo = null)
	{
		if (!$PathInfo)
		{
			$PathInfo = $this->GetPathInfo();

			array_shift($PathInfo);
		}

		$ArgumentList = array();

		while (count($PathInfo) > 0)
		{
			$Function = implode('_', $PathInfo);
			$Popped = array_pop($PathInfo);

			if (!method_exists($Object, $Function) || method_exists('Controller', $Function))
				$ArgumentList[] = $Popped;
			else
				$PathInfo = array();
		}

		// Reverse the argument list...
		$ArgumentList = array_reverse($ArgumentList);

		return $ArgumentList;
	}
	/**
	 * Runs the framework.
	 */
	public function Start()
	{
		$Controller = $this->GetController();

		$ControllerPath = Framework03::GetPath() . '/controllers/' . $Controller . '.php';

		if (!is_file($ControllerPath))
			throw new Exception('Page Not Found (' . $ControllerPath . ')', 404);

		// Include the controller
		require($ControllerPath);

		// Name of the class
		$Class = $Controller . 'Controller';

		// Create the controller
		$Object = new $Class;

		// Get the function
		$Function = $this->GetFunction($Object);

		if (!$Function)
			throw new Exception('The page "' . $Function . '" does not exist.', 404);

		$ArgumentList = $this->GetArgumentList($Object);
		
		// Let's make all posted data unsafe :) Safety should be handled by the user him self.
		if (get_magic_quotes_gpc())
			$_POST = Utils::StripSlashes($_POST);

		// Execute function
		$RenderDevice = $Object->$Function($ArgumentList);

		// Render the page
		if ($RenderDevice instanceof RenderDevice)
			$RenderDevice->Render();
		else
			throw new Exception('Page Not Found', 404);
	}
}

?>